package com.starsky.common.utils.reflection;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.lang.reflect.*;

/**
 * @author wansh
 * @version 1.0
 * @des 反射工具类
 * @email 1057718341@qq.com
 */
public class ReflectionUtils {
    private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);

    public ReflectionUtils() {
    }

    /**
     * 获取对象属性值
     *
     * @param obj：对象类
     * @param propertyName：属性名称
     * @return
     */
    public static Object invokeGetterMethod(Object obj, String propertyName) {
        String getterMethodName = "get" + StringUtils.capitalize(propertyName);
        return invokeMethod(obj, getterMethodName, new Class[0], new Object[0]);
    }

    /**
     * 给对象属性设置值
     *
     * @param obj：对象类
     * @param propertyName：属性名称
     * @param value：属性值
     */
    public static void invokeSetterMethod(Object obj, String propertyName, Object value) {
        invokeSetterMethod(obj, propertyName, value, null);
    }

    /**
     * 给对象属性设置值
     *
     * @param obj：对象类
     * @param propertyName：属性名称
     * @param value：属性值
     * @param propertyType：属性类型
     */
    public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) {
        Class type = propertyType != null ? propertyType : value.getClass();
        String setterMethodName = "set" + StringUtils.capitalize(propertyName);
        invokeMethod(obj, setterMethodName, new Class[]{type}, new Object[]{value});
    }

    /**
     * 获取对象属性值
     *
     * @param obj：对象类
     * @param fieldName：属性名称
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            Object result = null;
            try {
                result = field.get(obj);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常{}", var5);
            }
            return result;
        }
    }

    /**
     * 给对象属性设置值
     *
     * @param obj：对象类
     * @param fieldName：属性名称
     * @param value：属性值
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            try {
                field.set(obj, value);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常:{}", var5);
            }
        }
    }

    /**
     * 强制获取对象属性
     *
     * @param obj：对象类
     * @param fieldName：属性名称
     * @return
     */
    public static Field getAccessibleField(Object obj, String fieldName) {
        Assert.notNull(obj, "object不能为空");
        Assert.hasText(fieldName, "fieldName");
        Class superClass = obj.getClass();
        while (superClass != Object.class) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException var4) {
                superClass = superClass.getSuperclass();
            }
        }
        return null;
    }

    /**
     * 获取方法执行结果
     *
     * @param obj：对象类
     * @param methodName：方法名称
     * @param parameterTypes：方法参数类型
     * @param args：参数
     * @return
     */
    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args) {
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var6) {
                throw convertReflectionExceptionToUnchecked(var6);
            }
        }
    }

    /**
     * 强制获取私有方法
     *
     * @param obj：对象
     * @param methodName：方法名称
     * @param parameterTypes：参数类型
     * @return
     */
    public static Method getAccessibleMethod(Object obj, String methodName, Class... parameterTypes) {
        Assert.notNull(obj, "object不能为空");
        Class superClass = obj.getClass();
        while (superClass != Object.class) {
            try {
                Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
                method.setAccessible(true);
                return method;
            } catch (NoSuchMethodException var5) {
                superClass = superClass.getSuperclass();
            }
        }
        return null;
    }

    /**
     * 获取父类型
     *
     * @param clazz
     * @return
     */
    public static <T> Class<T> getSuperClassGenricType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    /**
     * 获取父类型
     *
     * @param clazz：类
     * @param index：获取父类型角标
     * @return
     */
    public static Class getSuperClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "\'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
            if (index < params.length && index >= 0) {
                if (!(params[index] instanceof Class)) {
                    logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class) params[index];
                }
            } else {
                logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "\'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }

    public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
        return !(e instanceof IllegalAccessException) && !(e instanceof IllegalArgumentException) && !(e instanceof NoSuchMethodException) ? (e instanceof InvocationTargetException ? new RuntimeException("Reflection Exception.", ((InvocationTargetException) e).getTargetException()) : (e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException("Unexpected Checked Exception.", e))) : new IllegalArgumentException("Reflection Exception.", e);
    }


    /**
     * <p>获取对象的字段名</p>
     * <pre>
     * </pre>
     *
     * @param o 对象
     * @return String[]
     */
    public static String[] getFiledName(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * <p>获取对象的值</p>
     * <pre>
     * </pre>
     *
     * @param o 对象
     * @return String[]
     */
    public static Object[] getFiledValues(Object o) {
        String[] fieldNames = getFiledName(o);
        Object[] value = new Object[fieldNames.length];
        for (int i = 0; i < fieldNames.length; i++) {
            value[i] = getFieldValueByName(fieldNames[i], o);
        }
        return value;
    }

    /**
     * <p>根据字段名获取值</p>
     * <pre>
     * </pre>
     *
     * @param fieldName 字段名
     * @param o         对象
     * @return Object
     */
    public static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, new Object[]{});
            return value;
        } catch (Exception e) {
            System.out.println("属性不存在");
            return null;
        }
    }

    /**
     * <p>根据字段名、注解名获取注解的内容</p>
     * <pre>
     * </pre>
     *
     * @param fieldName 字段名
     * @param annoName  注解名
     * @param o         对象
     * @return Object
     */
    public static Object getAnnotationByName(String fieldName, String annoName, Object o) {
        try {
            return null;
        } catch (Exception e) {
            System.out.println("属性不存在");
            return null;
        }
    }
}
